import time
import traceback
import configparser
import os
import sys
import win32print
import subprocess
import logging
import re
import requests
import json
import ast
import html
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
from threading import Thread
from dataclasses import dataclass
from queue import Queue, Empty

import tkinter as tk
from tkinter import ttk, messagebox, Toplevel, Listbox, END

sys.path.append(os.path.dirname(os.path.abspath(__file__)))

# 用于邮件通知
from urllib3 import disable_warnings
from urllib3.exceptions import InsecureRequestWarning
disable_warnings(InsecureRequestWarning) # 取消requests.get(verify=False)的warning SSL验证警告
from bs4 import BeautifulSoup

# 定义打印机配置的数据类
@dataclass
class PrinterConfig:
    section: str
    IP: str
    name: str
    prn_files: list
    prn_files_count: list
    print_interval: int
    group_interval: int
    current_page: int
    target_page: int
    log_name: str
    receiver_email: str

# 初始化日志记录器 (稍后在选择打印机后配置)
logger = logging.getLogger("PrinterSystem")

Init_Description = "未启动本次打印，特别注意初始页数设置！"
# --- GUI 应用核心类 ---

class PrinterApp:
    def __init__(self, root):
        self.root = root
        self.root.title("间歇打印控制器 - 奔图耗材运营中心")
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
        self.is_first_print_start = True

        # 状态变量
        self.selected_printer: PrinterConfig = None
        self.print_status = "暂停"  # "暂停", "打印中", "完成"
        self.print_status_description = Init_Description
        self.monitor_status = ""  # 记录监控的状态

        # 线程通信队列
        self.update_queue = Queue()
        
        # 读取配置并选择打印机
        printers = self.read_printer_config()
        if not printers:
            messagebox.showerror("配置错误", "错误: 没有在 '【双击修改】间歇打印配置.txt' 文件中找到任何打印机配置！")
            self.root.destroy()
            return

        choice = SelectPrinterDialog(self.root, printers).show()
        if choice is None:
            self.root.destroy()
            return
        
        self.selected_printer = printers[choice]

        # 初始化日志
        self.setup_logging()

        # 创建主界面
        self.style = ttk.Style()
        self.style.theme_use('default')  # 使用支持颜色定制的主题
        self.configure_progressbar_styles()
        self.create_widgets()
        
        # 启动后台任务
        self.start_background_tasks()

        # 启动UI更新循环
        self.process_queue()

    def configure_progressbar_styles(self):
        """配置进度条样式"""
        # 绿色进度条样式（打印中状态）
        self.style.configure("green.Horizontal.TProgressbar",
                            troughcolor='lightgray',
                            background='green',
                            bordercolor='darkgray')
        
        # 红色进度条样式（其他状态）
        self.style.configure("red.Horizontal.TProgressbar",
                            troughcolor='lightgray',
                            background='red',
                            bordercolor='darkgray')
        
    def create_widgets(self):
        """创建主窗口的UI组件"""
        # 创建Notebook (tabs控件)
        self.notebook = ttk.Notebook(self.root)
        self.notebook.pack(fill="both", expand=True, padx=10, pady=5)
        
        # 绑定tab切换事件
        self.notebook.bind("<<NotebookTabChanged>>", self.on_tab_changed)
        
        # --- 第一个tab: 详细信息 ---
        self.detail_tab = ttk.Frame(self.notebook)
        self.notebook.add(self.detail_tab, text="详细信息")
        
        # --- 第二个tab: 简洁显示 ---
        self.simple_tab = ttk.Frame(self.notebook)
        self.notebook.add(self.simple_tab, text="简洁显示")
        
        self.create_simple_tab()
        self.create_detail_tab()
        
        # 设置初始窗口大小
        self.set_window_size()

    def create_detail_tab(self):
        """创建详细信息tab"""
        # --- 顶部: 打印机配置 ---
        header_frame = ttk.LabelFrame(self.detail_tab, text="打印机当前配置", padding=10)
        header_frame.pack(fill="x", padx=10, pady=5)
        
        config_data = {
            "共享名": self.selected_printer.name,
            "IP地址": self.selected_printer.IP,
            "打印间隔时间": f"{self.selected_printer.print_interval}s",
            "打印组间隔时间": f"{self.selected_printer.group_interval}s",
            "当前日志文件": self.selected_printer.log_name
        }
        for i, (key, value) in enumerate(config_data.items()):
            ttk.Label(header_frame, text=f"{key}:").grid(row=i, column=0, sticky="w")
            ttk.Label(header_frame, text=value, foreground="blue").grid(row=i, column=1, sticky="w")

        ttk.Label(header_frame, text=f"打印文件列表（共{len(self.selected_printer.prn_files)}份）:").grid(row=len(config_data), column=0, columnspan=2, sticky="w", pady=(10, 0))
        
        prn_files_text = ""
        for i in range(len(self.selected_printer.prn_files)):
            prn_files_text += f" - {os.path.basename(self.selected_printer.prn_files[i])} (计{self.selected_printer.prn_files_count[i]}页)\n"
        
        ttk.Label(header_frame, text=prn_files_text.strip(), justify="left").grid(row=len(config_data) + 1, column=0, columnspan=2, sticky="w")

        # --- 中部: 打印任务信息 ---
        body_frame = ttk.LabelFrame(self.detail_tab, text="打印任务信息", padding=10)
        body_frame.pack(fill="x", padx=10, pady=5)
        
        # 使用Frame容器替代网格布局，避免标签和值间距变化
        self.status_vars = {
            'current_page': tk.StringVar(value=f"{self.selected_printer.current_page}页"),
            'target_page': tk.StringVar(value=f"{self.selected_printer.target_page}页"),
            'print_status': tk.StringVar(value=self.print_status),
            'print_status_desc': tk.StringVar(value=self.print_status_description),
            'monitor_status': tk.StringVar(value="监控未启动")
        }
        
        status_rows = [
            ("当前打印页数:", 'current_page'),
            ("目标打印页数:", 'target_page'),
            ("当前打印状态:", 'print_status'),
            ("具体状态描述:", 'print_status_desc'),
            ("后台监控状态:", 'monitor_status')
        ]
        
        self.status_labels = {}
        
        for i, (label_text, var_name) in enumerate(status_rows):
            row_frame = ttk.Frame(body_frame)
            row_frame.pack(fill="x", pady=2)
            
            # 标签
            ttk.Label(row_frame, text=label_text).pack(side="left", padx=(0, 10))
            
            # 值标签
            label = ttk.Label(row_frame, textvariable=self.status_vars[var_name], anchor="w")
            
            # 为状态标签设置特殊样式
            if var_name == 'print_status':
                label.config(font=('Helvetica', 10, 'bold'))
            
            label.pack(side="left", fill="x", expand=True)
            self.status_labels[var_name] = label

        # 进度条
        self.progress_bar = ttk.Progressbar(
            body_frame, 
            orient="horizontal", 
            length=300, 
            mode="determinate",
            style="red.Horizontal.TProgressbar"  # 初始为红色
        )
        self.progress_bar.pack(fill="x", pady=10)
        self.update_progress_bar()

        # --- 底部: 操作指引 ---
        footer_frame = ttk.LabelFrame(self.detail_tab, text="用户操作", padding=10)
        footer_frame.pack(fill="x", padx=10, pady=5)
        
        self.toggle_button = ttk.Button(footer_frame, text="开始打印", command=self.toggle_pause_resume)
        self.toggle_button.pack(side="left", padx=5)
        self.toggle_button.focus_set()
        self.root.bind('<Return>', lambda event=None: self.toggle_button.invoke())
        self.root.bind('<space>', lambda event=None: self.toggle_button.invoke())

        instructions = (
            " - 点击按钮或按\"空格键\"/\"回车键\"来切换打印状态。\n"
            " - 主动暂停或退出时，会自动保存当前已打印页数。\n"
            " - 如需修改配置，请修改 '【双击修改】间歇打印配置.txt' 文件后重启程序。"
        )
        ttk.Label(footer_frame, text=instructions, justify="left").pack(side="left", padx=10)
        
    def create_simple_tab(self):
        """创建简洁显示tab"""
        # 数字颜色映射 (1-9对应9种不同颜色)
        self.color_map = {
            0: "#9899C8",
            1: "#98D8C8",  # 薄荷绿
            2: "#4ECDC4",  # 青色
            3: "#45B7D1",  # 蓝色
            4: "#96CEB4",  # 绿色
            5: "#FFEAA7",  # 黄色
            6: "#DDA0DD",  # 紫色
            7: "#11D463",  # 深绿色
            8: "#F7DC6F",  # 浅黄色
            9: "#BB8FCE"   # 淡紫色
        }
        
        # 主容器
        main_frame = ttk.Frame(self.simple_tab)
        main_frame.pack(fill="both", expand=True, padx=20, pady=20)
        
        # 大数字显示
        self.big_number_frame = ttk.Frame(main_frame)
        self.big_number_frame.pack(fill="both", expand=True, pady=(0, 20))
        
        self.big_number_label = tk.Label(
            self.big_number_frame, 
            text="0",
            font=("Arial", 72, "bold"),
            bg=self.get_number_color(),
            fg="white",
            relief="raised",
            bd=3
        )
        self.big_number_label.pack(fill="both", expand=True)
        
        # 进度条
        self.simple_progress_bar = ttk.Progressbar(
            main_frame, 
            orient="horizontal", 
            length=400, 
            mode="determinate",
            style="red.Horizontal.TProgressbar"  # 初始为红色
        )
        self.simple_progress_bar.pack(fill="x", pady=(0, 10))
        
        self.simple_status_desc_var = tk.StringVar(value=self.print_status_description)
        self.simple_status_desc_label = ttk.Label(
            main_frame,
            textvariable=self.simple_status_desc_var,
            font=("Arial", 10),
            justify="center",
            foreground="red"  # 初始颜色，后续会根据状态变化
        )
        self.simple_status_desc_label.pack(fill="x", pady=(0, 10))
        
        # 状态信息
        self.simple_status_frame = ttk.Frame(main_frame)
        self.simple_status_frame.pack(fill="x")
        
        self.simple_status_var = tk.StringVar()
        self.update_simple_status()
        
        self.simple_status_label = ttk.Label(
            self.simple_status_frame,
            textvariable=self.simple_status_var,
            font=("Arial", 12),
            justify="center"
        )
        self.simple_status_label.pack(fill="x")

    def get_number_color(self):
        """根据当前section获取对应的颜色"""
        try:
            section_num = int(self.selected_printer.section[-1:])
            return self.color_map.get(section_num, "#CCCCCC")  # 默认灰色
        except (ValueError, IndexError, AttributeError):
            return "#CCCCCC"  # 默认灰色

    def update_simple_status(self):
        """更新简洁显示页面的状态"""
        current_page = getattr(self.selected_printer, 'current_page', 0)
        target_page = getattr(self.selected_printer, 'target_page', 0)
        
        status_text = f"进度：{current_page} / {target_page} "
        self.simple_status_var.set(status_text)

    def update_simple_display(self):
        """更新简洁显示页面的所有内容"""
        # 更新大数字
        section_num = self.selected_printer.section[len("打印机"):]
        self.big_number_label.config(
            text=section_num,
            bg=self.get_number_color()
        )
        
        # 更新进度条
        self.update_simple_progress()
        
        # 更新状态信息
        self.update_simple_status()

        # 更新状态描述
        self.simple_status_desc_var.set(self.print_status_description)
        
        # 根据状态设置颜色
        if self.print_status == "打印中":
            self.simple_status_desc_label.config(foreground="green")
        else:
            self.simple_status_desc_label.config(foreground="red")

    def update_simple_progress(self):
        """更新简洁显示页面的进度条"""
        current_page = getattr(self.selected_printer, 'current_page', 0)
        target_page = getattr(self.selected_printer, 'target_page', 1)  # 避免除零
        
        if target_page > 0:
            progress = (current_page / target_page) * 100
            self.simple_progress_bar['value'] = progress

    def on_tab_changed(self, event):
        """tab切换事件处理"""
        self.set_window_size()
        
        # 如果切换到简洁显示tab，更新显示内容
        current_tab = self.notebook.index(self.notebook.select())
        if current_tab == 1:  # 简洁显示tab
            self.update_simple_display()

    def set_window_size(self):
        """根据当前tab设置窗口大小"""
        current_tab = self.notebook.index(self.notebook.select())
        
        if current_tab == 0:  # 详细信息tab
            self.root.geometry("600x600")  # 原有大小
        else:  # 简洁显示tab
            self.root.geometry("300x300")  # 更小的尺寸

    def process_queue(self):
        """从队列中获取更新并应用到GUI"""
        try:
            while True:
                msg_type, value = self.update_queue.get_nowait()
                if msg_type == 'progress':
                    self.selected_printer.current_page = value
                    self.status_vars['current_page'].set(f"{value}页")
                    self.update_progress_bar()
                    self.update_simple_display()
                    
                elif msg_type == 'status':
                    self.print_status = value
                    self.status_vars['print_status'].set(value)
                    self.status_labels['print_status'].config(foreground='green' if value == '打印中' else 'red')
                    progress_style = "green.Horizontal.TProgressbar" if value == '打印中' else "red.Horizontal.TProgressbar"
                    self.progress_bar.config(style=progress_style)
                    self.simple_progress_bar.config(style=progress_style)
                    if value == "完成":
                        self.toggle_button.config(text="打印完成", state="disabled")
                    elif value == "打印中":
                        self.toggle_button.config(text="暂停打印")
                    elif value == "暂停":
                        self.toggle_button.config(text="继续打印")
                    self.update_simple_display()

                elif msg_type == 'status_desc':
                    self.print_status_description = value
                    self.status_vars['print_status_desc'].set(value)
                    self.status_labels['print_status_desc'].config(foreground='green' if self.print_status == '打印中' else 'red')
                    # 新增：同步更新简洁页面的状态描述
                    if hasattr(self, 'simple_status_desc_var'):
                        self.simple_status_desc_var.set(value)
                        if self.print_status == "打印中":
                            self.simple_status_desc_label.config(foreground="green")
                        else:
                            self.simple_status_desc_label.config(foreground="red")
                elif msg_type == 'monitor_status':
                    self.monitor_status = value
                    self.status_vars['monitor_status'].set(value)

                elif msg_type == 'error':
                    title, message = value
                    messagebox.showerror(title, message)
        
        except Empty:
            pass  # 队列为空，什么都不做
        finally:
            self.root.after(100, self.process_queue) # 每100ms检查一次队列

    def update_progress_bar(self):
        if self.selected_printer.target_page > 0:
            progress = (self.selected_printer.current_page / self.selected_printer.target_page) * 100
            self.progress_bar['value'] = progress
        else:
            self.progress_bar['value'] = 0

    def toggle_pause_resume(self):
        """处理暂停/继续按钮的点击事件"""
        if self.is_first_print_start:
            self.notebook.select(1)
            self.is_first_print_start = False

        if self.print_status == "打印中":
            new_status = "暂停"
            desc = "用户主动暂停"
            logger.info(desc)
            self.save_current_page_to_config() # 主动暂停时保存进度
        elif self.print_status == "暂停":
            new_status = "打印中"
            desc = "用户主动恢复打印"
            logger.info(desc)
        else:
            return # '完成'状态下无操作

        self.update_queue.put(('status', new_status))
        self.update_queue.put(('status_desc', desc))
    
    def on_closing(self):
        """处理窗口关闭事件"""
        if self.print_status != "完成" and self.selected_printer:
            if messagebox.askyesno("退出", "打印任务尚未完成，确定要退出吗？\n(当前进度将会被保存)"):
                self.save_current_page_to_config()
                self.root.destroy()
            else:
                return
        else:
            self.root.destroy()

    def start_background_tasks(self):
        """启动所有后台线程"""
        # 启动打印线程
        print_thread = Thread(target=self.printing, daemon=True)
        print_thread.start()

        # 启动监控线程
        if self.selected_printer.IP:
            monitor_thread = Thread(target=self.monitor_printer_status, daemon=True)
            monitor_thread.start()
    
    def setup_logging(self):
        """配置日志记录器"""
        global logger
        logger.setLevel(logging.DEBUG)
        # 避免重复添加handler
        if not logger.handlers:
            fh = logging.FileHandler(self.selected_printer.log_name)
            fh.setLevel(logging.DEBUG)
            formatter = logging.Formatter("%(asctime)s - %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
            fh.setFormatter(formatter)
            logger.addHandler(fh)
        logger.debug("打印系统GUI初始化")

    def read_printer_config(self):
        config = configparser.ConfigParser()
        config_file = '【双击修改】间歇打印配置.txt'
        
        if not os.path.exists(config_file):
            return []
            
        config.read(config_file, encoding='utf-8')
        printers = []
        
        for section in config.sections():
            if section.startswith('打印机'):
                try:
                    prn_files, prn_files_count = [], []
                    i = 1
                    while True:
                        key = f'Prn文件名称{i}'
                        if key in config[section]:
                            prn_files.append('prn文件存放/' + config[section][key])
                            count_key = f'Prn文件{i}页数'
                            prn_files_count.append(int(config[section].get(count_key, 1)))
                            i += 1
                        else:
                            break
                    
                    printer = PrinterConfig(
                        section=section,
                        IP=config[section]['打印机IP地址'],
                        name=config[section]['打印机名称'],
                        prn_files=prn_files,
                        prn_files_count=prn_files_count,
                        print_interval=int(config[section]['打印间隔时间_秒']),
                        group_interval=int(config[section]['打印组间隔时间_秒']),
                        current_page=int(config[section]['已打印页数']),
                        target_page=int(config[section]['打印总页数']),
                        log_name=config[section]['打印日志名称'],
                        receiver_email = config[section]['收信息邮箱']
                    )
                    printers.append(printer)
                except Exception as e:
                    messagebox.showwarning("配置解析错误", f"读取配置段 '{section}' 时发生错误: {e}\n该配置将被跳过。")
                    continue
        return printers

    def save_current_page_to_config(self):
        config = configparser.ConfigParser()
        config_file = '【双击修改】间歇打印配置.txt'
        config.read(config_file, encoding='utf-8')
        
        if self.selected_printer.section in config:
            config[self.selected_printer.section]['已打印页数'] = str(self.selected_printer.current_page)
        
        with open(config_file, 'w', encoding='utf-8') as configfile:
            config.write(configfile)
            
        logger.info(f"已保存当前打印页数 {self.selected_printer.current_page} 到配置文件")

    # 辅助函数：专门用来检查打印机队列是否为空
    def is_printer_queue_empty(self,printer_name):
        """
        检查指定打印机的队列是否为空。
        这个函数会打开、检查、然后立即关闭打印机句柄，避免长时间占用。
        """
        hprinter = None  # 确保在任何情况下 hprinter 都有定义
        try:
            # PRINTER_ACCESS_USE 是一个比默认权限更轻量级的访问级别，仅用于查看
            access_rights = win32print.PRINTER_ACCESS_USE 
            hprinter = win32print.OpenPrinter(printer_name, {'DesiredAccess': access_rights})
            jobs = win32print.EnumJobs(hprinter, 0, -1, 1)
            return len(jobs) == 0
        finally:
            if hprinter:
                win32print.ClosePrinter(hprinter)

    def print_prn_file(self, prn_file, printer_name):
        computer_name = os.environ.get('COMPUTERNAME')
        if not os.path.isfile(prn_file):
            raise RuntimeError(f"错误：{prn_file} 文件不存在！")

        self.update_queue.put(('status_desc', f"检查打印机 '{printer_name}' 队列..."))
        
        # 循环检查队列，直到它为空
        while not self.is_printer_queue_empty(printer_name):
            self.update_queue.put(('status_desc', "等待打印队列清空...(每2秒重新检查一次)"))
            time.sleep(2)
            
        self.update_queue.put(('status_desc', f"队列已清空，准备打印 {os.path.basename(prn_file)}"))

        # 在没有任何 win32print 句柄打开的情况下，安全地发送打印作业
        try:
            command = f'copy /B "{os.path.abspath(prn_file)}" "\\\\{computer_name}\\{printer_name}"'
            result = subprocess.run(
                command, shell=True, check=True, capture_output=True, text=True, encoding='gbk'
            )

            self.update_queue.put(('status_desc', f"文件 {os.path.basename(prn_file)} 已发送至打印机。"))

        except subprocess.CalledProcessError as e:
            # 捕获更具体的异常，并提供详细的错误信息
            error_msg = f"打印失败: 命令 '{e.cmd}' 返回码 {e.returncode}\n标准输出: {e.stdout}\n标准错误: {e.stderr}"
            raise RuntimeError(error_msg)
        except Exception as e:
            # 捕获其他可能的异常
            raise RuntimeError(f"打印过程中发生未知错误: {e}")

    def printing(self):
        prns_len = len(self.selected_printer.prn_files)
        if prns_len == 0:
            logger.error("错误：文件列表为空！")
            self.update_queue.put(('error', ("打印错误", "错误：PRN文件列表为空！")))
            return
        
        logger.info("===== 开始打印任务 =====")
        logger.info(f"打印机序号: {self.selected_printer.section}")
        logger.info(f"打印机名称: {self.selected_printer.name}")
        logger.info(f"打印机IP: {self.selected_printer.IP}")
        logger.info(f"初始页数: {self.selected_printer.current_page}")
        logger.info(f"目标页数: {self.selected_printer.target_page}")
        logger.info(f"打印间隔: {self.selected_printer.print_interval}秒")
        logger.info(f"打印组间隔: {self.selected_printer.group_interval}秒")
        logger.info(f"PRN文件数量: {prns_len}")
        for i in range(len(self.selected_printer.prn_files)):
            logger.info(f"Prn文件名称{i+1}: {self.selected_printer.prn_files[i]}，其页数计数为：{self.selected_printer.prn_files_count[i]}")
        
        total_pages_count = sum(self.selected_printer.prn_files_count)
        index_select_count = []
        temp_count = 0
        for c in self.selected_printer.prn_files_count:
            temp_count += c
            index_select_count.append(temp_count)
            
        while True:
            if self.print_status == "完成":
                break
            
            time.sleep(0.5) # 减少CPU占用
            
            try:
                if self.print_status == "打印中":
                    remainder = self.selected_printer.current_page % total_pages_count
                    file_index = 0
                    for i, count in enumerate(index_select_count):
                        if remainder < count:
                            file_index = i
                            break
                    
                    self.update_queue.put(('status_desc', "启动打印中..."))
                    file_to_print = self.selected_printer.prn_files[file_index]
                    self.print_prn_file(file_to_print, self.selected_printer.name)
                    
                    self.selected_printer.current_page += self.selected_printer.prn_files_count[file_index]
                    self.update_queue.put(('progress', self.selected_printer.current_page))
                    logger.info(f"当前打印进度: {self.selected_printer.current_page}/{self.selected_printer.target_page}页")
                    
                    if self.selected_printer.current_page >= self.selected_printer.target_page:
                        self.selected_printer.current_page = self.selected_printer.target_page
                        self.update_queue.put(('progress', self.selected_printer.current_page))
                        self.update_queue.put(('status', "完成"))
                        completion_msg = "已完成当前打印任务，现在可关闭本程序"
                        self.update_queue.put(('status_desc', completion_msg))
                        logger.info("===== 打印任务完成 =====")
                        self.save_current_page_to_config()
                        break
                    
                    if file_index == 0:
                        time.sleep(self.selected_printer.group_interval)
                    else:
                        time.sleep(self.selected_printer.print_interval)

            except Exception as e:
                if self.print_status != "完成":
                    self.update_queue.put(('status', "暂停"))
                
                pause_msg = "异常暂停，详情见弹窗"
                self.update_queue.put(('status_desc', pause_msg))
                
                exc_info = "".join(traceback.format_exception(type(e), e, e.__traceback__))
                logger.error(f"打印过程中发生异常: {str(e)}\n{exc_info}")
                self.update_queue.put(('error', (f"[bold red]{self.selected_printer.section}:打印过程发生异常[/bold red]", exc_info)))

    def monitor_printer_status(self):
        logger.info("已启动打印状态监控")
        series_of_254 = ["254", "252", "452"]
        series_of_553 = ["553", "554"]
        series_of_MX60 = ["271", "3081", "3071"]
        series_of_4030 = ["4030"]
        
        get_DevStatus = None
        if any(series in self.selected_printer.name for series in series_of_254):
            logger.info("【打印监控】确认为254系列打印机")
            get_DevStatus = self.get_DevStatus_HP_254
        elif any(series in self.selected_printer.name for series in series_of_553):
            logger.info("【打印监控】确认为553系列打印机")
            get_DevStatus = self.get_DevStatus_HP_553
        elif any(series in self.selected_printer.name for series in series_of_MX60):
            logger.info("【打印监控】确认为MX60系列打印机")
            get_DevStatus = self.get_DevStatus_Sharp_MX60
        elif any(series in self.selected_printer.name for series in series_of_4030):
            logger.info("【打印监控】确认为Samsung 4030系列打印机")
            get_DevStatus = self.get_DevStatus_Samsung_4030
        else:
            msg = "不能确认打印机系列，无法开启监控。"
            logger.info("【打印监控】" + msg)
            self.update_queue.put(('monitor_status', msg))
            return

        while True:
            time.sleep(1)
            if self.print_status == "完成":
                break
            
            ok, status = get_DevStatus()
            
            # 只有在非用户主动暂停时，监控才干预打印状态
            if self.print_status_description != Init_Description and self.print_status_description != "用户主动暂停" and self.print_status != "完成":
                if ok:
                    # 打印机等待中，我们也暂停
                    if status.startswith("等待"):
                        if self.print_status == "打印中":
                            self.update_queue.put(('status', "暂停"))
                    # 打印机状态正常，我们应该恢复打印
                    else:
                        if self.print_status == "暂停":
                           self.update_queue.put(('status', "打印中"))
                    
                    if status != self.monitor_status:
                        self.update_queue.put(('monitor_status', status))
                        logger.info(f"监控打印状态：{str(ok)}，描述：{status}")
                else: # 监控到异常
                    if self.print_status == "打印中":
                        self.update_queue.put(('status', "暂停"))

                    self.update_queue.put(('status_desc', status))
                    
                    if status != self.monitor_status and self.selected_printer.receiver_email:
                        try:
                            logger.warning(f"检测到打印机异常状态，发送邮件通知: {status}")
                            self.send_mail(status, self.selected_printer.receiver_email)
                        except Exception as e:
                            logger.error(f"发送邮件失败: {str(e)}")
                        
                        self.update_queue.put(('monitor_status', status))

    def get_DevStatus_HP_254(self):
        IP = self.selected_printer.IP
        url = f"http://{IP}/info_deviceStatus.html?tab=Home&menu=DevStatus"
        headers = {
                "Host": IP,
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:130.0) Gecko/20100101 Firefox/130.0",
                "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
                "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
                "Accept-Encoding": "gzip, deflate",
                "Connection": "keep-alive",
                "Referer": f"http://{IP}/info_suppliesStatus.html?tab=Home&menu=SupplyStatus",
                "Upgrade-Insecure-Requests": "1",
                "Priority": "u=0, i"
            }
        try:
            response = requests.get(url, headers=headers, verify=False, timeout=5)
            soup = BeautifulSoup(response.text, 'html.parser')
            target_td = soup.find('td', class_='itemLargeFont', id='deviceStatus_tableCell')
            if target_td:
                status_text = re.sub(r'\s+', '', target_td.get_text(strip=True).replace('\xa0', ' '))
                ok_keywords = ["正在打印文档", "就绪", "睡眠模式"]
                wait_keywords = ["正在初始化", "正在清洁", "正在散热", "正在校准"]
                if any(keyword in status_text for keyword in ok_keywords): return True, "正常：" + status_text
                if any(keyword in status_text for keyword in wait_keywords): return True, "等待：" + status_text
                return False, "异常：" + status_text
            return True, "失败：获取打印机状态失败，请手动控制中断"
        except requests.exceptions.Timeout: return True, "请求超时，请检查网络或重试，或手动控制中断"
        except Exception: return True, "失败：解析打印机状态时出错，请手动控制中断"

    def get_DevStatus_HP_553(self):
        IP = self.selected_printer.IP
        url = f"http://{IP}/"
        headers = {
                "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
                "Accept-Encoding": "gzip, deflate, br, zstd",
                "Accept-Language": "zh-CN,zh;q=0.9",
                "Cache-Control": "max-age=0",
                "Connection": "keep-alive",
                "Cookie": "sessionId=0e95756ab6284df1901b2f7f521b8e5d",
                "Host": IP,
                "Sec-Fetch-Dest": "document",
                "Sec-Fetch-Mode": "navigate",
                "Sec-Fetch-Site": "none",
                "Sec-Fetch-User": "?1",
                "Upgrade-Insecure-Requests": "1",
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
                "sec-ch-ua": '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
                "sec-ch-ua-mobile": "?0",
                "sec-ch-ua-platform": '"Windows"'
            }

        try:
            response = requests.get(url, headers=headers, verify=False, timeout=5)
            soup = BeautifulSoup(response.text, 'html.parser')
            target_span = soup.find('span', id='MachineStatus')
            if target_span:
                status_text = re.sub(r'\s+', '', target_span.get_text(strip=True).replace('\xa0', ' '))
                ok_keywords = ["正在打印", "就绪", "睡眠模式", "耗材严重不足", "耗材不足"]
                wait_keywords = ["正在初始化", "正在清洁", "正在散热", "正在校准", "正在检查"]
                if any(keyword in status_text for keyword in ok_keywords): return True, "正常：" + status_text
                if any(keyword in status_text for keyword in wait_keywords): return True, "等待：" + status_text
                return False, "异常：" + status_text
            return True, "失败：获取打印机状态失败，请手动控制中断"
        except requests.exceptions.Timeout: return True, "请求超时，请检查网络或重试，或手动控制中断"
        except Exception: return True, "失败：解析打印机状态时出错，请手动控制中断"

    def get_DevStatus_Sharp_MX60(self):
        IP = self.selected_printer.IP
        url = f"http://{IP}/main.html"
        headers = {
                "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
                "Accept-Encoding": "gzip, deflate",
                "Accept-Language": "zh-CN,zh;q=0.9",
                "Cache-Control": "max-age=0",
                "Connection": "keep-alive",
                "Cookie": "sideBarflag=1; MFPSESSIONID=1500B2BD773D7BCEBE490807A1FAFE38B024B27EE9E6A4CD641320250619075418617200A8",
                "Host": IP,
                "Upgrade-Insecure-Requests": "1",
                "User-Agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Mobile Safari/537.36"
            }
        try:
            response = requests.get(url, headers=headers, verify=False, timeout=5)
            soup = BeautifulSoup(response.text, 'html.parser')
            status_td = soup.find('td', class_='noserch')
            if status_td:
                status_text = re.sub(r'\s+', '', status_td.get_text(strip=True).replace('\xa0', ' '))
                ok_keywords = ["墨粉较少", "打印机警告", "更换墨粉回收容器", "在线", "忙碌", "超过维护期"]
                wait_keywords = ["指定纸盒已被打开", "盖板打开"]
                if any(keyword in status_text for keyword in ok_keywords): return True, "正常：" + status_text
                if any(keyword in status_text for keyword in wait_keywords): return True, "等待：" + status_text
                return False, "异常：" + status_text
            return True, "失败：获取打印机状态失败，请手动控制中断"
        except requests.exceptions.Timeout: return True, "请求超时，请检查网络或重试，或手动控制中断"
        except Exception: return True, "失败：解析打印机状态时出错，请手动控制中断"

    def parse_javascript_object(self, text):
        """
        解析JavaScript对象字面量格式（非标准JSON）为Python字典
        
        Args:
            text: JavaScript对象字面量格式的字符串
            
        Returns:
            dict: 解析后的字典，如果失败返回None
        """
        try:
            # 清理文本：移除制表符，统一空格
            text = text.replace('\t', ' ')
            
            # 处理HTML实体（如 &#x2F; 转换为 /）
            # 先保护字符串内的内容
            strings = []
            string_pattern = r'"[^"]*"'
            
            def replace_string(m):
                idx = len(strings)
                strings.append(m.group(0))
                return f'__STRING_{idx}__'
            
            # 临时替换字符串
            text_no_strings = re.sub(string_pattern, replace_string, text)
            
            # 处理HTML实体（在字符串外）
            text_no_strings = html.unescape(text_no_strings)
            
            # 给键名加引号（匹配 word: 模式）
            # 需要更精确的匹配，避免匹配已引用的键和值
            # 匹配模式：单词字符后跟冒号，但前面不能是引号或数字
            text_no_strings = re.sub(r'([a-zA-Z_][a-zA-Z0-9_]*)\s*:', r'"\1":', text_no_strings)
            
            # 恢复字符串
            for idx, string in enumerate(strings):
                text_no_strings = text_no_strings.replace(f'__STRING_{idx}__', string)
            
            # 使用ast.literal_eval解析（Python字典字面量格式）
            return ast.literal_eval(text_no_strings)
        except Exception as e:
            logger.error(f"解析JavaScript对象失败: {e}")
            return None

    def get_DevStatus_Samsung_4030(self):
        IP = self.selected_printer.IP
        url = f"https://{IP}/sws/app/information/home/home.json"
        headers = {
                "Accept": "*/*",
                "Accept-Encoding": "gzip, deflate, br, zstd",
                "Accept-Language": "zh-CN,zh;q=0.9",
                "Connection": "keep-alive",
                "Cookie": "language=en; xuser=SWS2.0; login=true",
                "Host": IP,
                "Referer": f"https://{IP}/sws/index.html",
                "Sec-Fetch-Dest": "empty",
                "Sec-Fetch-Mode": "cors",
                "Sec-Fetch-Site": "same-origin",
                "User-Agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36",
                "sec-ch-ua": '"Google Chrome";v="141", "Not?A_Brand";v="8", "Chromium";v="141"',
                "sec-ch-ua-mobile": "?1",
                "sec-ch-ua-platform": '"Android"'
            }
        try:
            response = requests.get(url, headers=headers, verify=False, timeout=5)
            response.raise_for_status()
            
            # 获取响应文本（可能是JavaScript对象字面量格式，不是标准JSON）
            text = response.text
            
            # 解析响应（支持标准JSON和JavaScript对象字面量格式）
            data = self.parse_javascript_object(text)
            
            if data is None:
                return True, "失败：解析响应数据失败，请手动控制中断"
            
            # 从响应中获取状态信息
            if 'status' in data:
                hr_device_status = data['status'].get('hrDeviceStatus')
                status1 = data['status'].get('status1', '')
                
                # 根据需求：值为2时是可以正常打印的状态，3时是有异常的状态
                if hr_device_status == 2:
                    # 正常状态
                    status_text = status1 if status1 else "就绪"
                    return True, "正常：" + status_text
                elif hr_device_status == 3:
                    # 异常状态
                    status_text = status1 if status1 else "异常"
                    return False, "异常：" + status_text
                else:
                    # 其他状态值，暂时作为等待状态处理
                    status_text = status1 if status1 else f"未知状态({hr_device_status}：{status1})"
                    return True, "等待：" + status_text
            else:
                return True, "失败：响应中未找到status字段，请手动控制中断"
        except requests.exceptions.Timeout:
            return True, "请求超时，请检查网络或重试，或手动控制中断"
        except json.JSONDecodeError:
            return True, "失败：解析JSON响应时出错，请手动控制中断"
        except Exception as e:
            return True, f"失败：获取打印机状态时出错({str(e)})，请手动控制中断"

    def send_mail(self, text, receiver_email):
        if not receiver_email: return
        smtp_server, port = "smtp.qq.com", 465
        sender_email, password = "3568605467@qq.com", "zjkhvpkahiwrcjei"
        msg = MIMEText(text)
        msg["Subject"] = "打印机异常"
        msg["From"] = formataddr(("打印机监控系统", sender_email))
        msg["To"] = receiver_email
        with smtplib.SMTP_SSL(smtp_server, port) as server:
            server.login(sender_email, password)
            server.sendmail(sender_email, receiver_email, msg.as_string())

class SelectPrinterDialog(Toplevel):
    """一个用于选择打印机的模式对话框"""
    def __init__(self, parent, printers):
        super().__init__(parent)
        self.transient(parent)
        self.title("选择打印机")
        self.printers = printers
        self.result = None
        self.attributes('-topmost', True)
        self.listbox = Listbox(self, width=100, height=20)
        self.listbox.pack(padx=10, pady=10)

        for p in printers:
            self.listbox.insert(END, f"{p.section}: {p.name} ({p.log_name[:-4]}) - 已打印{p.current_page}/{p.target_page}页")
        
        if self.printers:
            self.listbox.select_set(0)

        button_frame = ttk.Frame(self)
        button_frame.pack(padx=10, pady=(0, 10))

        ok_button = ttk.Button(button_frame, text="确定", command=self.on_ok)
        ok_button.pack(side="left", padx=5)

        cancel_button = ttk.Button(button_frame, text="取消", command=self.on_cancel)
        cancel_button.pack(side="left", padx=5)

        self.grab_set()
        self.geometry("+%d+%d" % (parent.winfo_rootx()+50, parent.winfo_rooty()+50))
        self.protocol("WM_DELETE_WINDOW", self.on_cancel)
        self.wait_window(self)

    def on_ok(self):
        selections = self.listbox.curselection()
        if selections:
            self.result = selections[0]
            self.destroy()

    def on_cancel(self):
        self.result = None
        self.destroy()

    def show(self):
        return self.result

if __name__ == "__main__":
    if not os.path.exists('【双击修改】间歇打印配置.txt'):
         messagebox.showerror("错误", "配置文件 '【双击修改】间歇打印配置.txt' 不存在！\n程序无法启动。")
    else:
        root = tk.Tk()
        app = PrinterApp(root)
        if not app.selected_printer: # 如果在选择打印机时关闭了对话框
             pass # root 已经被 destroy
        else:
             root.mainloop()